package com.base.cn.platform.os.service.user.account;

import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.mybatis.Pagination;
import com.base.cn.platform.os.common.utils.DataUtil;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.common.utils.user.AccountBizType;
import com.base.cn.platform.os.common.utils.user.AccountHistoryType;
import com.base.cn.platform.os.common.utils.user.AccountStatus;
import com.base.cn.platform.os.dao.user.account.CusUserAccountDao;
import com.base.cn.platform.os.entity.order.order.Order;
import com.base.cn.platform.os.entity.user.account.CusUserAccount;
import com.base.cn.platform.os.entity.user.account.CusUserAccountColumns;
import com.base.cn.platform.os.entity.user.account.CusUserAccountHistory;
import com.base.cn.platform.os.entity.user.account.CusUserAccountHistoryColumns;
import com.base.cn.platform.os.entity.user.user.CusUser;
import com.base.cn.platform.os.entity.user.user.UserCondition;
import com.base.cn.platform.os.service.user.user.CusUserBiz;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 账户Service
 *
 * @author ll
 * @create 2018-04-24
 */
@Service
public class CusUserAccountBiz extends BaseBiz<CusUserAccount,CusUserAccountDao> {

    @Autowired
    private CusUserBiz cusUserBiz;
    @Autowired
    private CusUserAccountHistoryBiz cusUserAccountHistoryBiz;

    /**
     * 用户提现申请不通过时回退金额
     * @param userId 用户ID
     * @param sysUserId 操作用户ID
     * @param refundCashPrice 退金额
     */
    @Transactional(rollbackFor =  IllegalArgumentException.class)
    public void userAccountRefundCash(BigDecimal userId,BigDecimal sysUserId,double refundCashPrice){
        CusUserAccount userAccount = this.queryUserAccountByUserId(userId,false);
        BigDecimal price = new BigDecimal(refundCashPrice);
        userAccount.setBalance(userAccount.getBalance().add(price));
        userAccount.setApplyCashAmount(userAccount.getApplyCashAmount().subtract(price));
        userAccount.setCashAmount(userAccount.getCashAmount().add(price));
        cusUserAccountHistoryBiz.addHistory(userAccount,price, AccountHistoryType.REFUND_CASH.getValue(),BigDecimal.ZERO,null,null,true, AccountBizType.CASH.getValue(),sysUserId);
        this.updateById(userAccount,null);
    }

    /**
     * 用户账户提现
     * @param userAccount 用户账户对象
     * @param cashPrice 提现金额
     */
    @Transactional(rollbackFor =  IllegalArgumentException.class)
    public void userAccountCash(CusUserAccount userAccount,double cashPrice){
        BigDecimal price = new BigDecimal(cashPrice);
        userAccount.setBalance(userAccount.getBalance().subtract(price));
        userAccount.setCashAmount(userAccount.getCashAmount().subtract(price));
        userAccount.setApplyCashAmount(userAccount.getApplyCashAmount().add(price));
        cusUserAccountHistoryBiz.addHistory(userAccount,price, AccountHistoryType.CASH.getValue(),BigDecimal.ZERO,null,null,true, AccountBizType.CASH.getValue(),BigDecimal.ZERO);
        this.updateById(userAccount,null);
    }

    /**
     * 账户入账,充值 入款，出账.消费
     *
     * @param userId             学员用户id
     * @param trxAmount          　交易金额
     * @param accountType        　账户操作类型，cash or vm
     * @param accountHistoryType 　账户历史记录类型
     * @param orderId            　订单号,订单表主键id
     * @param orderNo            　订单号,对系统的的
     * @param outTradeNo         　提交到支付宝的,(充值卡是用卡号)
     * @param isDisplay          　在用户我的账户历史中是否显示 0显示 1不显示
     * @param accountBizType     　交易类型，课程、会员、图书等
     * @param createUserId          后台管理ID
     * @param status             1.出账 2.进账
     */
    public void updateAccountMoney(BigDecimal userId,
                                   double trxAmount,
                                   String accountType,
                                   String accountHistoryType,
                                   BigDecimal orderId,
                                   String orderNo,
                                   String outTradeNo,
                                   boolean isDisplay,
                                   String accountBizType,
                                   BigDecimal createUserId,
                                   int status, boolean isIos) throws Exception{
        if (DataUtil.idIsNotNull(userId)) {
            CusUserAccount userAccount = this.queryUserAccountByUserId(userId,false);
            if (status == 1) {
                this.tx_debit(userAccount, new BigDecimal(trxAmount), accountHistoryType, orderId, orderNo, outTradeNo, isDisplay, accountBizType, createUserId);
            }
            if (status == 2) {
                this.tx_credit(userAccount, new BigDecimal(trxAmount), accountType, accountHistoryType, orderId, orderNo, outTradeNo, isDisplay, accountBizType, createUserId,isIos);
            }
        }
    }

    /**
     * 获取用户的账户
     *
     * @param userId 用户ID
     * @return UserAccount
     */
    public CusUserAccount queryUserAccountByUserId(BigDecimal userId,boolean userData) {
        if (ObjectUtils.isNotEmpty(userId)){
            CusUserAccount userAccount = this.findOne("userId="+userId,null);
            if(ObjectUtils.isEmpty(userAccount)){//如果用户账号不存在，则创建用户账号
                this.createUserAccount(userId);
            }
            if(userData){
                this.setUserByAccount(userAccount);
            }
            return  userAccount;
        }
        return null;
    }

    /**
     * 创建用户账户
     *
     * @param userId 用户 id
     */
    public void createUserAccount(BigDecimal userId){
        List<CusUserAccount> list = setCusUserAccountData(userId.toString());
        if(!list.isEmpty()){
            this.save(list.get(0));
        }
    }

    /**
     * 批量创建用护账户
     *
     * @param userIds 用户id串 id
     */
    public void createBatchUserAccount(String userIds){
        List<CusUserAccount> list = setCusUserAccountData(userIds);
        this.batchSave(list);
    }

    public String  whereSql(CusUserAccountColumns cusUserAccount){
        String whereSql = " 1=1 ";
        if(ObjectUtils.isNotEmpty(cusUserAccount)){
            if (ObjectUtils.isNotEmpty(cusUserAccount.getUserIds())){
                whereSql += " and userId in ("+cusUserAccount.getUserIds()+")";
            }
            if(ObjectUtils.isNotEmpty(cusUserAccount.getUserId())){
                whereSql += " and userId ="+cusUserAccount.getUserId();
            }
            if(ObjectUtils.isNotEmpty(cusUserAccount.getAccountStatus())){
                whereSql += " and accountStatus='"+cusUserAccount.getAccountStatus()+"'";
            }
            if (ObjectUtils.isNotEmpty(cusUserAccount.getVersion())){
                whereSql += " and version='"+cusUserAccount.getVersion()+"'";
            }
        }
        whereSql += " order by id desc";
        return whereSql;
    }

    /**
     * 查询用户所有账户数据（分页）
     *
     * @param userContainColumns 查询条件
     * @param page               分页条件
     */
    public PageInfo<CusUserAccount> queryAllUserAccountListPage(UserCondition userContainColumns, Pagination page) {
        PageInfo<CusUserAccount> userAccounts = new PageInfo<>();
        String whereSql = "";
        boolean s = false;
        if (StringUtils.isNotEmpty(userContainColumns)) {
            String _where = cusUserBiz.whereUserSql(userContainColumns);
            whereSql =_where;
            _where=StringUtils.replace(_where,"1=1","");
            if(StringUtils.isNotEmpty(_where.trim())){
                s = true;
            }
        }
        List<CusUser> userList = null;
        if (s) {
            userList = cusUserBiz.find(whereSql,null,new ArrayList<>());
        }
        String userIds = "";
        if (ObjectUtils.isNotEmpty(userList) && userList.size() > 0) {
            userIds =  userList.stream().map(e -> e.getId().toString()).distinct().collect(Collectors.joining(","));
        }
        List<CusUserAccount> userAccountList = null;
        if (s == false || (s == true && StringUtils.isNotEmpty(userIds))) {
            CusUserAccountColumns  cusUserAccountColumns= new CusUserAccountColumns();
            if (StringUtils.isNotEmpty(userIds)){
                cusUserAccountColumns.setUserIds(userIds);
            }
            String _whereSql=this.whereSql(cusUserAccountColumns);
            userAccounts = this.findPage(_whereSql,page,new ArrayList<>());
            if (ObjectUtils.isNotEmpty(userAccounts)){
                userAccountList =userAccounts.getList();
            }
        }
        if (ObjectUtils.isNotEmpty(userAccountList) && userAccountList.size() > 0) {
            userIds = userAccountList.stream().map(e -> e.getUserId().toString()).distinct().collect(Collectors.joining(","));;
            userList = cusUserBiz.queryUserByIds(userIds,false,false,false,false,false,false,false);
            Map<BigDecimal, CusUser> userMap = userList.stream().collect(Collectors.toMap(CusUser::getId, e -> e));
            if (userMap != null && userMap.size() > 0) {
                for (CusUserAccount userAccount : userAccountList) {
                    userAccount.setUser(userMap.get(userAccount.getUserId()));
                }
            }
            userAccounts.setList(userAccountList);
        }
        return userAccounts;
    }

    /**
     * 操作账户金额（仅用于后台管理员的操作功能，别的功能不能调用该方法）
     * type=1银行充值，type=2银行冻结金额,type=3银行解冻金额
     * type=4充值卡入账,type=5充值卡冻结金额,type=6充值卡解冻金额
     * type=7银行扣款，type=8充值卡扣款
     * type=9银行退款，type=10充值卡退款
     *type = 11 积分兑换
     * @param createUserId 后台操作人
     * @param userAccount      账户
     * @param type    操作类型
     * @param amount  操作金额
     */
    @Transactional(rollbackFor =  IllegalArgumentException.class)
    public void tx_updateUserAccountAmount(CusUserAccount userAccount, BigDecimal createUserId, int type, double amount, Order order) {
        this.updateById(userAccount,null);//执行更新
        //添加消费记录
        cusUserAccountHistoryBiz.addUserAccountHistory(createUserId, userAccount, type, new BigDecimal(amount),order);
    }

    /**
     * 添加用户
     *
     * @param userAccount
     */
    public void setUserByAccount(CusUserAccount userAccount) {
        if (ObjectUtils.isNotEmpty(userAccount)) {
            CusUser user = cusUserBiz.findById(userAccount.getUserId());
            userAccount.setUser(user);
        }
    }

    /**
     * 账户扣款，消费，出账
     *
     * @param userAccount
     * @param trxAmount          交易金额
     * @param accountHistoryType 账户历史记录类型
     * @param orderId            订单号,订单表主键id
     * @param orderNo            订单号,对外的
     * @param outTradeNo         第三方流水号
     * @param isDisplay          在用户我的账户历史中是否显示
     * @param accountBizType     交易类型，课程、会员、图书、商品等
     * @param createUserId   后台管理员账号
     */
    @Transactional(rollbackFor =  IllegalArgumentException.class)
    public CusUserAccount tx_debit(CusUserAccount userAccount,
                                   BigDecimal trxAmount,
                                   String accountHistoryType,
                                   BigDecimal orderId,
                                   String orderNo,
                                   String outTradeNo,
                                   boolean isDisplay,
                                   String accountBizType, BigDecimal createUserId) throws Exception {
        BigDecimal curBalance = userAccount.getBalance();
        System.out.println("---------------------curBalance:" + curBalance);
        System.out.println("---------------------trxAmount:" + trxAmount);
        DecimalFormat df = new DecimalFormat("0.00");
        if (Double.parseDouble(df.format(curBalance.doubleValue())) < Double.parseDouble(df.format(trxAmount.doubleValue())))
            throw new IllegalArgumentException("余额不足");
        try {
            logger.info("debit befor:======balance:" + curBalance + "=====trxAmount:" + trxAmount + "============");
            userAccount.debit(trxAmount);// 扣除操作,cash ,vm具体在此方法中
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
        //更新账户
        this.updateUserAccount(userAccount);
        //添加操作记录
        cusUserAccountHistoryBiz.addHistory(userAccount, trxAmount, accountHistoryType, orderId, orderNo, outTradeNo, isDisplay, accountBizType, createUserId);
        return userAccount;
    }

    /**
     * 账户入账,充值 入款
     *
     * @param userAccount
     * @param trxAmount          　交易金额
     * @param accountType        　账户操作类型，cash 现金  or vm  虚拟的，充值卡，课程卡
     * @param accountHistoryType 　账户历史记录类型
     * @param orderId            　订单号,订单表主键id
     * @param orderNo            　订单号,对系统的的
     * @param out_trade_no       　提交到支付宝的,(充值卡是用卡号)
     * @param isDisplay          　在用户我的账户历史中是否显示 0显示 1不显示
     * @param accountBizType     　交易类型，课程、会员、图书等
     * @param createUserId   　后台管理员名
     */
    @Transactional(rollbackFor =  IllegalArgumentException.class)
    public CusUserAccount tx_credit(CusUserAccount userAccount,
                                    BigDecimal trxAmount,
                                    String accountType,
                                    String accountHistoryType,
                                    BigDecimal orderId,
                                    String orderNo,
                                    String out_trade_no,
                                    boolean isDisplay,
                                    String accountBizType,
                                    BigDecimal createUserId,
                                    boolean isIos) throws Exception {
        BigDecimal curBalance = userAccount.getBalance();
        try {
            logger.info("credit befor:======balance:" + curBalance + "=====trxAmount:" + trxAmount + "============");
            userAccount.credit(trxAmount, accountType);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
        // 每次充值都有out_trade_no，防止重复充值做查询判断
        // 查询账户历史是否用out_trade_no，如果有了。抛出异常
        List<CusUserAccountHistory> userAccountHistoryList = new ArrayList<>();
        if(StringUtils.isNotEmpty(out_trade_no)){
            CusUserAccountHistoryColumns cusUserAccountHistory = new CusUserAccountHistoryColumns();
            cusUserAccountHistory.setOutTradeNo(out_trade_no);
            userAccountHistoryList= cusUserAccountHistoryBiz.queryUserAccountHistoryList(cusUserAccountHistory,true);
        }

        if (!isIos&&userAccountHistoryList != null && userAccountHistoryList.size() > 0) {
            throw new IllegalArgumentException("已经充值过，不可重新充值");
        }
        //更新账户
        this.updateUserAccount(userAccount);
        //添加操作记录
        cusUserAccountHistoryBiz.addHistory(userAccount, trxAmount, accountHistoryType, orderId, orderNo, out_trade_no, isDisplay, accountBizType, createUserId);
        logger.info("credit SUCCESS:======balance:" + userAccount.getBalance() + "=====trxAmount:" + trxAmount + "============");
        return userAccount;
    }

    /**
     * 更新用户账户
     *
     * @param userAccount 用户账户属性对象
     */
    private void updateUserAccount(CusUserAccount userAccount) {
        userAccount.setVersion(userAccount.getVersion() + 1);
        this.updateById(userAccount, null);
    }

    /**
     * 初始化账户数据（创建）
     * @param userIds
     */
    private List<CusUserAccount> setCusUserAccountData(String userIds){
        List<CusUserAccount> list = new ArrayList<>();
        String[] splitUserIds = userIds.split(",");
        for (String userId:
                splitUserIds) {
            CusUserAccount cusUserAccount = new CusUserAccount();
            cusUserAccount.setUserId(new BigDecimal(userId));
            cusUserAccount.setAccountStatus(AccountStatus.ACTIVE.toString());
            cusUserAccount.setStatus(1);
            list.add(cusUserAccount);
        }
        return list;
    }

}
